package com.nineclock.sign.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itzhanshen.sys.feign.SysUserFeign;
import com.nineclock.common.entity.PageResult;
import com.nineclock.common.enums.ResponseEnum;
import com.nineclock.common.exception.NCException;
import com.nineclock.common.utils.BeanHelper;
import com.nineclock.common.utils.CurrentUserHolder;
import com.nineclock.common.utils.DateTimeUtil;
import com.nineclock.dto.SysCompanyUserDTO;
import com.nineclock.dto.SysDepartmentDTO;
import com.nineclock.sign.dto.SignAllUserDTO;
import com.nineclock.sign.dto.SignDTO;
import com.nineclock.sign.dto.SignInfoDTO;
import com.nineclock.sign.dto.SignPCListDTO;
import com.nineclock.sign.excel.CustomHandler;
import com.nineclock.sign.mapper.SignInfoMapper;
import com.nineclock.sign.mapper.SignPictureMapper;
import com.nineclock.sign.pojo.SignInfo;
import com.nineclock.sign.pojo.SignPicture;
import com.nineclock.sign.service.SignService;
import jdk.nashorn.internal.ir.LiteralNode;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Transactional
public class SignServiceImpl implements SignService {
    @Autowired
    SignInfoMapper signInfoMapper;
    @Autowired
    SignPictureMapper signPictureMapper;
    @Autowired
    SysUserFeign sysUserFeign;

    /**
     * 导出签到数据
     *
     * @param startTime
     * @param endTime
     */
    @Override
    public void export(String startTime, String endTime) {
        // 获取指定时间段的签到信息
        List<String> spanDateList = getSpanDateList(startTime, endTime);
        List<SignPCListDTO> signPCListDTOS = querySigns(startTime, endTime, spanDateList);
        List<List<SignInfoDTO>> signs = signPCListDTOS.stream().map(signPCListDTO -> {
            return signPCListDTO.getSigns();
        }).collect(Collectors.toList());
        //设置文件下载的头信息
        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
        response.setHeader("Content-disposition", "attachment;filename=Attendance.xls");
        response.setContentType("application/octet-stream;charset=UTF-8");
        response.setCharacterEncoding("utf-8");

        //写入Excel
        try {
            EasyExcel.write(response.getOutputStream())
                    .excelType(ExcelTypeEnum.XLS)
                    .head(handleHeader(signs.get(0))) //表头
                    .registerWriteHandler(new CustomHandler()) //设置列宽
                    .registerWriteHandler(horizontalCellStyleStrategy()) //设置水平居中
                    .sheet("签到记录")
                    .doWrite(handleData(signPCListDTOS)); // 数据
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //设置样式
    public HorizontalCellStyleStrategy horizontalCellStyleStrategy() {

        WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
        //内容策略 - 水平居中
        contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);

        //设置字体
        WriteFont font = new WriteFont();
        font.setFontName("阿里巴巴普惠体");
        font.setFontHeightInPoints((short) 11);
        contentWriteCellStyle.setWriteFont(font);

        HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(contentWriteCellStyle, contentWriteCellStyle);

        return horizontalCellStyleStrategy;
    }

    //组装导出数据中的数据
    private List<List<String>> handleData(List<SignPCListDTO> signPCListDTOS) {
        List<List<String>> dataList = new ArrayList<List<String>>();
        // 封装基本数据   //姓名, 工号, 部门, 职位
        if (signPCListDTOS != null) {

            signPCListDTOS.stream().forEach(signPCListDTO -> {
                List<String> list = new ArrayList<>();
                list.add(signPCListDTO.getUsername());
                list.add(signPCListDTO.getWorkNumber());
                list.add(signPCListDTO.getDepartment().getName());
                list.add(signPCListDTO.getPost());
                //动态信息 : 每日打卡情况
                List<SignInfoDTO> signs = signPCListDTO.getSigns();
                if (signs != null) {
                    for (SignInfoDTO sign : signs) {
                        list.add(String.valueOf(sign.getSignCount()));
                    }

                }
                dataList.add(list);
            });

        }
        return dataList;
    }

    //组装表头信息
    private List<List<String>> handleHeader(List<SignInfoDTO> signInfoDTOS) {
        List<List<String>> headers = new ArrayList<List<String>>();

        headers.add(Arrays.asList("姓名"));
        headers.add(Arrays.asList("工号"));
        headers.add(Arrays.asList("部门"));
        headers.add(Arrays.asList("职位"));

        //动态表头
        for (SignInfoDTO signInfoDTO : signInfoDTOS) {
            headers.add(Arrays.asList(signInfoDTO.getSignDate()));
        }

        return headers;
    }

    /**
     * PC端 分页展示不同时间段的签到记录
     *
     * @param startTime
     * @param endTime
     * @param page
     * @param pageSize
     * @return
     */
    @Override
    public PageResult<SignPCListDTO> querySignByPage(String startTime, String endTime, Integer page, Integer pageSize) {
        // 获取日期的列表
        List<String> dateList = getSpanDateList(startTime, endTime);
        // 分页查询数据
        Page<SignInfo> pages = new Page<>(page, pageSize);
        LambdaQueryWrapper<SignInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SignInfo::getCompanyId, CurrentUserHolder.get().getCompanyId());
        queryWrapper.between(SignInfo::getCreateDate, startTime, endTime);
        pages = signInfoMapper.selectPage(pages, queryWrapper);
        List<SignInfo> signInfos = pages.getRecords();
        if (signInfos != null) {
            List<SysCompanyUserDTO> sysCompanyUserDTOList = signInfos.stream().map(signInfo -> {
                // 根据员工ID查询员工信息
                return sysUserFeign.findCompanyUserById(signInfo.getCompanyUserId()).getData();

            }).collect(Collectors.toList());

            // 组装基本数据
            Set<SignPCListDTO> collect = sysCompanyUserDTOList.stream().map(sysCompanyUserDTO -> {
                SignPCListDTO signPCListDTO = new SignPCListDTO();
                signPCListDTO.setUsername(sysCompanyUserDTO.getUserName());
                signPCListDTO.setPost(sysCompanyUserDTO.getPost());
                signPCListDTO.setWorkNumber(sysCompanyUserDTO.getWorkNumber());
                // 封装部门信息
                Long departmentId = sysCompanyUserDTO.getDepartmentId();
                String departmentName = sysCompanyUserDTO.getDepartmentName();
                SysDepartmentDTO sysDepartmentDTO = new SysDepartmentDTO();
                sysDepartmentDTO.setId(departmentId);
                sysDepartmentDTO.setName(departmentName);
                signPCListDTO.setDepartment(sysDepartmentDTO);

                // 组装当前日期以及日期的签到次数
                List<SignInfoDTO> signInfoDTOS = this.handleSignEveryDay(dateList, sysCompanyUserDTO.getId());

                signPCListDTO.setSigns(signInfoDTOS);
                return signPCListDTO;
            }).collect(Collectors.toSet());
            // 去重
            List<SignPCListDTO> signPCListDTOS = new ArrayList<>(collect);
            // 返回数据
            return new PageResult<>(pages.getTotal(), pages.getPages(), signPCListDTOS);
        }

        return null;
    }

    // 查询每天日期的考勤记录,并进行封装
    private List<SignInfoDTO> handleSignEveryDay(List<String> dateList, Long companyUserId) {
        List<SignInfoDTO> list = new ArrayList<>();
        // 获取每一天签到的情况
        dateList.stream().forEach(date -> {

            LambdaQueryWrapper<SignInfo> queryWrapper = new LambdaQueryWrapper<>();
            SignInfoDTO signInfoDTO = new SignInfoDTO();
            queryWrapper.eq(SignInfo::getCreateDate, date);
            queryWrapper.eq(SignInfo::getCompanyUserId, companyUserId);
            Integer count = signInfoMapper.selectCount(queryWrapper);
            signInfoDTO.setSignDate(date);
            signInfoDTO.setSignCount(count);
            list.add(signInfoDTO);
        });
        return list;
    }


    // 获取日期的时间列表
    private List<String> getSpanDateList(String startTime, String endTime) {
        List<Date> dates = DateTimeUtil.getDatesBetweenTwoDate(startTime, endTime, DateTimeUtil.TIME_FORMAT_2);
        List<String> dateTimes = dates.stream().map(date -> {
            return DateTimeUtil.dateToStr(date, DateTimeUtil.TIME_FORMAT_2);
        }).collect(Collectors.toList());
        return dateTimes;
    }

    /**
     * 签到
     *
     * @param signDTO
     */
    @Override
    public void sign(SignDTO signDTO) {
        // 参数校验
        if (signDTO == null) {
            throw new NCException(ResponseEnum.MESSAGE_PARAMS_LOST);
        }
        // 获取公司相关参数
        Long companyId = CurrentUserHolder.get().getCompanyId();
        Long companyUserId = CurrentUserHolder.get().getCompanyUserId();
        // 组装签到参数
        SignInfo signInfo = BeanHelper.copyProperties(signDTO, SignInfo.class);
        signInfo.setCompanyId(companyId);
        signInfo.setCompanyUserId(companyUserId);
        Date date = new Date();
        signInfo.setCreateTime(date);
        // 组装签到月和签到时间 ==字符串   private String createMonth;   private String createDate;
        String createDate = DateTimeUtil.dateToStr(date, DateTimeUtil.TIME_FORMAT_2);
        signInfo.setCreateDate(createDate);
        String createMonth = DateTimeUtil.dateToStr(date, DateTimeUtil.TIME_FORMAT_4);
        signInfo.setCreateMonth(createMonth);
        System.out.println(signDTO.getImages());
        // 添加到数据库
        signInfoMapper.insert(signInfo);
        // 添加图片的保存地址
        String images = signDTO.getImages();
        SignPicture signPicture = new SignPicture();
        signPicture.setSignId(signInfo.getId());
        signPicture.setUrl(images);
        signPictureMapper.insert(signPicture);
    }

    /**
     * 获取当天当前用户签到次数
     *
     * @return
     */
    @Override
    public Integer queryUserSignCount() {
        // 获取到当前用户
        Long companyId = CurrentUserHolder.get().getCompanyId();
        Long companyUserId = CurrentUserHolder.get().getCompanyUserId();
        // 获取当天的时间
        Date date = new Date();
        String toDayTime = DateTimeUtil.dateToStr(date, DateTimeUtil.TIME_FORMAT_2);
        // 组装查询条件
        LambdaQueryWrapper<SignInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SignInfo::getCompanyId, companyId);
        queryWrapper.eq(SignInfo::getCompanyUserId, companyUserId);
        queryWrapper.eq(SignInfo::getCreateDate, toDayTime);
        Integer count = signInfoMapper.selectCount(queryWrapper);
        return count;
    }

    /**
     * 获取用户当前当月签到记录
     *
     * @param dateStr
     * @return
     */
    @Override
    public List<SignDTO> queryUserMonthSignCount(String dateStr) {
        // 参数校验
        if (dateStr == null) {
            throw new NCException(ResponseEnum.MESSAGE_PARAMS_LOST);
        }
        // 组装查询条件
        LambdaQueryWrapper<SignInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SignInfo::getCompanyId, CurrentUserHolder.get().getCompanyId());
        queryWrapper.eq(SignInfo::getCreateMonth, dateStr);

        // 根据月份查询当月签到数量
        List<SignInfo> signInfos = signInfoMapper.selectList(queryWrapper);

        List<SignDTO> resultSign = BeanHelper.copyWithCollection(signInfos, SignDTO.class);

        List<String> imagesUrls = new ArrayList<>();
        // 根据文档ID查询图片列表
        if (resultSign != null) {

            resultSign.stream().forEach(signDTO -> {
                LambdaQueryWrapper<SignPicture> pictureWrapper = new LambdaQueryWrapper<>();
                pictureWrapper.eq(SignPicture::getSignId, signDTO.getId());
                SignPicture signPicture = signPictureMapper.selectOne(pictureWrapper);

                // 签到图片地址列表
                if (signPicture != null) {
                    String imagesUrl = signPicture.getUrl();
                    // 组装图片列表   // 组装数据返回
                    signDTO.setImages(imagesUrl);

                    // 封装签到图片地址列表
                    imagesUrls.add(imagesUrl);

                    if (imagesUrls != null) {

                        signDTO.setSignPictureUrlList(imagesUrls);
                    }

                }
            });
            return resultSign;
        }
        return null;
    }

    /**
     * 统计当前当前日期所有员工的打卡信息
     *
     * @param dateStr
     * @return
     */
    @Override
    public List<SignAllUserDTO> queryAllCompanyUserSignCount(String dateStr) {
        if (dateStr == null) {
            throw new NCException(ResponseEnum.MESSAGE_PARAMS_LOST);
        }
        // 查询当日签到记录
        Integer count = signInfoMapper.TodaySignCount(dateStr);
        String todaySignCount = String.valueOf(count);

        List<SignAllUserDTO> result = new ArrayList<>();
        // 查询当前企业所有员工
        List<SysCompanyUserDTO> companyUserDTOList = sysUserFeign.queryAllCompanyUsers().getData();
        if (companyUserDTOList != null) {
            companyUserDTOList.stream().forEach(sysCompanyUserDTO -> {
                // 根据员工iD & 当前时间 查询签到记录
                LambdaQueryWrapper<SignInfo> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(SignInfo::getCompanyUserId, sysCompanyUserDTO.getId());
                queryWrapper.eq(SignInfo::getCompanyId, sysCompanyUserDTO.getCompanyId());
                queryWrapper.eq(SignInfo::getCreateDate, dateStr);
                List<SignInfo> signInfos = signInfoMapper.selectList(queryWrapper);
                if (signInfos != null) {
                    List<SignDTO> signDTOList = BeanHelper.copyWithCollection(signInfos, SignDTO.class);
                    // 组装签到数据 && 组装用户名 && 组装当日签到数量 && 图片信息
                    for (SignDTO signDTO : signDTOList) {

                        signDTO.setDayCount(todaySignCount);  // 当日签到记录
                        signDTO.setUserName(sysCompanyUserDTO.getUserName()); // 签到二级用户名
                        // 组装返回数据
                        SignAllUserDTO signAllUserDTO = new SignAllUserDTO();
                        signAllUserDTO.setSignResponseList(signDTOList);
                        signAllUserDTO.setUsername(sysCompanyUserDTO.getUserName());
                        result.add(signAllUserDTO);
                    }
                }
                // 返回数据
            });
            Set<SignAllUserDTO> set = new HashSet<>(result);
            List<SignAllUserDTO> signAllUserDTOS = new ArrayList<>(set);
            return result;
        }
        return null;
    }

    // 导出数据使用的查询签到数据
    public List<SignPCListDTO> querySigns(String startTime, String endTime, List<String> dateList) {
        // 获取日期的列表
        // 分页查询数据
        LambdaQueryWrapper<SignInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SignInfo::getCompanyId, CurrentUserHolder.get().getCompanyId());
        queryWrapper.between(SignInfo::getCreateDate, startTime, endTime);
        List<SignInfo> signInfos = signInfoMapper.selectList(queryWrapper);
        if (signInfos != null) {
            List<SysCompanyUserDTO> sysCompanyUserDTOList = signInfos.stream().map(signInfo -> {
                // 根据员工ID查询员工信息
                return sysUserFeign.findCompanyUserById(signInfo.getCompanyUserId()).getData();

            }).collect(Collectors.toList());

            // 组装基本数据
            Set<SignPCListDTO> collect = sysCompanyUserDTOList.stream().map(sysCompanyUserDTO -> {
                SignPCListDTO signPCListDTO = new SignPCListDTO();
                signPCListDTO.setUsername(sysCompanyUserDTO.getUserName());
                signPCListDTO.setPost(sysCompanyUserDTO.getPost());
                signPCListDTO.setWorkNumber(sysCompanyUserDTO.getWorkNumber());
                // 封装部门信息
                Long departmentId = sysCompanyUserDTO.getDepartmentId();
                String departmentName = sysCompanyUserDTO.getDepartmentName();
                SysDepartmentDTO sysDepartmentDTO = new SysDepartmentDTO();
                sysDepartmentDTO.setId(departmentId);
                sysDepartmentDTO.setName(departmentName);
                signPCListDTO.setDepartment(sysDepartmentDTO);

                // 组装当前日期以及日期的签到次数
                List<SignInfoDTO> signInfoDTOS = this.handleSignEveryDay(dateList, sysCompanyUserDTO.getId());

                signPCListDTO.setSigns(signInfoDTOS);
                return signPCListDTO;
            }).collect(Collectors.toSet());
            // 去重
            List<SignPCListDTO> signPCListDTOS = new ArrayList<>(collect);
            // 返回数据
            return signPCListDTOS;
        }
        return null;
    }
}
